// vue插件：
// 要求必须有install方法 将来在vue.use中调用
let Vue; // 保存vue构造函数 插件中使用
class VueRouter {
  constructor(options) {
    // 保存路由数据
    this.$options = options;
    // 把current作为响应式数据  将来发生变化   router-view函数能再次执行
    this.current = window.location.hash.slice(1) || '/';
    // Vue.util.defineReactive 为vue暴露出来的方法  在发生变化时 所有依赖的地方会重新执行
    // Vue.util.defineReactive(this, 'current', initial)

    // 为嵌套路由设置当前的路由的路由数组（为当前路径的所有路由）
    Vue.util.defineReactive(this, "matched", []);
    this.match();
    // 监听hash变化
    //   window.addEventListener('hashchange', () => {
    //     // console.log(e);
    //     // console.log(window.location.hash, window.location.hash.slice(1));
    //     this.current = window.location.hash.slice(1)
    //   })
    window.addEventListener("hashchange", this.onHashChange.bind(this));
    window.addEventListener("load", this.onHashChange.bind(this));
  }
  // 清空路由数组并调用重新设置函数
  onHashChange() {
    // console.log(window.location.hash);
    this.current = window.location.hash.slice(1);
    this.matched = [];
    this.match();
  }
  match(routes) {
    routes = routes || this.$options.routes;
    for (const route of routes) {
      // 如果前挡路由为根路由
      if (route.path === "/" && this.current === "/") {
        // 为路由添加当前根路由后退出
        this.matched.push(route);
        return;
      }
      // 如果当前路由的路径不为/并且当前url包含当前路由的path，则将前端路由添加到路由数组
      if (route.path !== "/" && this.current.indexOf(route.path) !== -1) {
        this.matched.push(route);
        // 如果当前的路由有children则递归循环
        if (route.children) {
          this.match(route.children);
        }
        return;
      }
    }
  }
}

VueRouter.install = function (_Vue) {
  Vue = _Vue;

  // 1.挂载$router属性
  // 全局混入
  // 全局混入的目的:延迟下边的逻辑到router创建完毕并附加到选项时才执行
  Vue.mixin({
    beforeCreate() {
      // 此狗子函数在没和组件创建实例时都会调用
      // 只有根实例才会拥有该选项this.$options.router
      if (this.$options.router) {
        Vue.prototype.$router = this.$options.router;
      }
    },
  });

  // 2.注册并实现两个组件：router-view, router-link
  Vue.component("router-link", {
    props: {
      to: {
        type: String,
        require: true,
      },
    },
    render(h) {
      return h(
        "a",
        { attrs: { href: `#${this.to}` } },
        this.$slots.default //获取默认插槽的内容
      );
      // return <a href={`#${this.to}`} >{this.$slots.default}</a>
    },
  });
  Vue.component("router-view", {
    render(h) {
      // 初始化组件
      // let component = null;
      // 循环寻找当前路由对应的组件
      // const route = this.$router.$options.routes.find(route => route.path === this.$router.current)
      // 存在则赋值
      // if (route) {
      //   component = route.component;
      // }
      // TODO    以上为单层路由的解决方法  下方为嵌套路由的解决
      // 标记当前组件为router-view组件
      this.$vnode.data.routerView = true;
      // 设置当前路由深度
      let depth = 0;
      // 获取父组件
      let parent = this.$parent;
      // 循环寻找父组件直到根组件
      while (parent) {
        // 拿到父组件的data
        const vnodeData = parent.$vnode && parent.$vnode.data;
        if (vnodeData) {
          // 查看父组件是否被标记为router-view组件  如果被标记为router-view组件则深度+1
          if (vnodeData.routerView) {
            depth++;
          }
        }
        // 循环结束时重新赋值
        parent = parent.$parent;
      }
      let component = null;
      // 只有域名或端口和ip时赋值/
      window.location.hash = window.location.hash == "" ? "/" : window.location.hash;
      // 拿到深度之后将本层需要的router从路由数组中拿出
      let route = this.$router.matched[depth];
      // 将组件取出赋值给component
      if (route) {
        component = route.component;
      }
      return h(component);
    },
  });
};

export default VueRouter;
